#include <uxr/agent/AgentInstance.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <fstream>
#include <ctime>
#include <sstream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <thread>
#include <mutex>
#include <iomanip>
#include <ucdr/microcdr.h>
#include <uxr/client/client.h>

using namespace std;

struct student {
    string name;
    long number;
    long grade;
    vector<string> hobby;
};

mutex mtx;
vector<student> students;
const int MAX_STUDENTS = 1000;

string current_datetime() {
    time_t now = time(nullptr);
    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y%m%d%H%M%S", localtime(&now));
    return buffer;
}

void write_to_file(const vector<student>& students, const string& filename) {
    ofstream file(filename);
    if (!file.is_open()) {
        cerr << "无法打开文件: " << filename << endl;
        return;
    }

    for (const auto& s : students) {
        file << s.name << "," << s.number << "," << s.grade << "," << s.hobby[0] << "," << s.hobby[1] << "," << s.hobby[2] << "\n";
    }
    file.close();
    cout << "数据已写入文件: " << filename << endl;
}

bool deserialize_student(uint8_t* buffer, size_t length, student& s) {
    ucdrBuffer reader;
    ucdr_init_buffer(&reader, buffer, length);

    char name[256];
    if (!ucdr_deserialize_string(&reader, name, sizeof(name))) return false;
    s.name = string(name);

    int32_t number, grade;
    if (!ucdr_deserialize_int32_t(&reader, &number)) return false;
    if (!ucdr_deserialize_int32_t(&reader, &grade)) return false;
    s.number = number;
    s.grade = grade;

    char hobby1[256], hobby2[256], hobby3[256];
    if (!ucdr_deserialize_string(&reader, hobby1, sizeof(hobby1))) return false;
    if (!ucdr_deserialize_string(&reader, hobby2, sizeof(hobby2))) return false;
    if (!ucdr_deserialize_string(&reader, hobby3, sizeof(hobby3))) return false;
    s.hobby = { string(hobby1), string(hobby2), string(hobby3) };

    // 打印反序列化后的数据
    cout << "反序列化学生数据: " << s.name << ", " << s.number << ", " << s.grade
         << ", " << s.hobby[0] << ", " << s.hobby[1] << ", " << s.hobby[2] << endl;

    return true;
}

void handle_udp_data(uint8_t* buffer, size_t length) {
    student s;
    if (!deserialize_student(buffer, length, s)) {
        cerr << "反序列化学生数据失败" << endl;
        return;
    }

    unique_lock<mutex> lock(mtx);
    students.push_back(s);
    if (students.size() >= MAX_STUDENTS) {
        sort(students.begin(), students.end(), [](const student& a, const student& b) {
            return a.number < b.number;
        });
        string filename = "../" + current_datetime() + ".txt";
        write_to_file(students, filename);
        students.clear();
    }
}

void handle_tcp_data(const string& data) {
    istringstream ss(data);
    string name, number, grade, hobby1, hobby2, hobby3;
    getline(ss, name, ',');
    getline(ss, number, ',');
    getline(ss, grade, ',');
    getline(ss, hobby1, ',');
    getline(ss, hobby2, ',');
    getline(ss, hobby3, '\n');

    student s;
    s.name = name;
    s.number = stol(number);
    s.grade = stol(grade);
    s.hobby = {hobby1, hobby2, hobby3};

    cout << "接收到TCP数据: " << s.name << ", " << s.number << ", " << s.grade
         << ", " << s.hobby[0] << ", " << s.hobby[1] << ", " << s.hobby[2] << endl;

    unique_lock<mutex> lock(mtx);
    students.push_back(s);
    if (students.size() >= MAX_STUDENTS) {
        sort(students.begin(), students.end(), [](const student& a, const student& b) {
            return a.number < b.number;
        });
        string filename = "../" + current_datetime() + ".txt";
        write_to_file(students, filename);
        students.clear();
    }
}

void start_tcp_server(short port) {
    int server_fd;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        cerr << "创建套接字失败" << endl;
        exit(EXIT_FAILURE);
    }

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        cerr << "设置套接字选项失败" << endl;
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(port);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
        cerr << "绑定套接字失败" << endl;
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    if (listen(server_fd, 3) < 0) {
        cerr << "监听套接字失败" << endl;
        close(server_fd);
        exit(EXIT_FAILURE);
    }

    while (true) {
        int client_sock;
        if ((client_sock = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
            cerr << "接受连接失败" << endl;
            close(server_fd);
            exit(EXIT_FAILURE);
        }
        thread([client_sock]() {
            try {
                while (true) {
                    char data[1024];
                    int bytes_read = read(client_sock, data, sizeof(data));
                    if (bytes_read <= 0) {
                        unique_lock<mutex> lock(mtx);
                        if (!students.empty()) {
                            string filename = "../" + current_datetime() + ".txt";
                            write_to_file(students, filename);
                            students.clear();
                        }
                        break;
                    }
                    handle_tcp_data(string(data, bytes_read));
                }
            } catch (exception& e) {
                cerr << "线程中发生异常: " << e.what() << "\n";
            }
            close(client_sock);
        }).detach();
    }
}

void start_udp_server(short port) {
    int sockfd;
    struct sockaddr_in server_addr, client_addr;
    socklen_t addr_len = sizeof(client_addr);
    uint8_t buffer[1024];

    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        cerr << "创建UDP套接字失败" << endl;
        exit(EXIT_FAILURE);
    }

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(port);

    if (bind(sockfd, (const struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
        cerr << "绑定UDP套接字失败" << endl;
        close(sockfd);
        exit(EXIT_FAILURE);
    }

    while (true) {
        int len = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_addr, &addr_len);
        if (len > 0) {
            handle_udp_data(buffer, len);
        }
    }

    close(sockfd);
}

void handle_fastdds_data(const uint8_t* buffer, size_t length) {
    student s;
    if (!deserialize_student(const_cast<uint8_t*>(buffer), length, s)) {
        cerr << "反序列化学生数据失败" << endl;
        return;
    }

    unique_lock<mutex> lock(mtx);
    students.push_back(s);
    if (students.size() >= MAX_STUDENTS) {
        sort(students.begin(), students.end(), [](const student& a, const student& b) {
            return a.number < b.number;
        });
        string filename = "../" + current_datetime() + ".txt";
        write_to_file(students, filename);
        students.clear();
    }
}

void fastdds_listener_function(/* parameters to get data from FastDDS */) {
    // Placeholder function to simulate receiving data from FastDDS
    // This function should be replaced with actual FastDDS data receiving logic
    uint8_t buffer[1024];
    size_t length = sizeof(buffer);
    // Simulate receiving data into buffer
    handle_fastdds_data(buffer, length);
}

int center_main() {
    thread tcp_thread1(start_tcp_server, 12345);
    thread tcp_thread2(start_tcp_server, 12346);
    thread udp_thread(start_udp_server, 2010);
    thread fastdds_thread(fastdds_listener_function);

    tcp_thread1.join();
    tcp_thread2.join();
    // udp_thread.join();
    fastdds_thread.join();
    return 0;
}

int main(int argc, char** argv)
{
    eprosima::uxr::AgentInstance& agent_instance = eprosima::uxr::AgentInstance::getInstance();
    if (!agent_instance.create(argc, argv))
    {
        return 1;
    }

    std::thread agent_thread([&]()
    {
        agent_instance.run();
    });

    std::thread center_thread(center_main);

    agent_thread.join();
    center_thread.join();

    return 0;
}
